/* Copyright 2012 Tobias Marschall
 * 
 * This file is part of CLEVER.
 * 
 * CLEVER is free software: you can redistribute it and/or modify
 * it under the terms of the GNU General Public License as published by
 * the Free Software Foundation, either version 3 of the License, or
 * (at your option) any later version.
 *
 * CLEVER is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 * GNU General Public License for more details.
 *
 * You should have received a copy of the GNU General Public License
 * along with CLEVER.  If not, see <http://www.gnu.org/licenses/>.
 */

#include <iostream>

#include <boost/iostreams/device/file.hpp>
#include <boost/iostreams/filtering_stream.hpp>
#include <boost/iostreams/filter/gzip.hpp>
#include <boost/program_options.hpp>

#include "SequenceUtils.h"
#include "GroupWiseBamReader.h"
#include "ShortDnaSequence.h"
#include "VersionInfo.h"

using namespace std;
namespace po = boost::program_options;
namespace io = boost::iostreams;


void usage(const char* name, const po::options_description& options_desc) {
	cerr << "Usage: " << name << " [options] <output.1.fastq> <output.2.fastq>" << endl;
	cerr << endl;
	cerr << "Reads BAM format from stdin and produces FASTQ output." << endl;
	cerr << endl;
	cerr << options_desc << endl;
	exit(1);
}

void output_read(const BamTools::BamAlignment& aln, ostream& output) {
	bool reverse = false;
	if (aln.IsMapped() && aln.IsReverseStrand()) reverse = true;
	ShortDnaSequence seq(aln.QueryBases, aln.Qualities);
	if (reverse) seq = seq.reverseComplement();
	output << "@" << aln.Name << endl;
	output << seq << endl;
	output << '+' << endl;
	output << seq.qualityString() << endl;
}

int main(int argc, char* argv[]) {
	VersionInfo::checkAndPrintVersion("bam2fastq", cerr);
	string commandline = VersionInfo::commandline(argc, argv);

	po::options_description options_desc("Allowed options");
	
	if (isatty(fileno(stdin)) || (argc<3)) {
	// if (argc<4) {
		usage(argv[0], options_desc);
	}
	
	string output1_filename(argv[argc-2]);
	string output2_filename(argv[argc-1]);
	argc -= 2;

	ofstream output1(output1_filename.c_str());
	if (output1.fail()) {
		cerr << "Error: could not open " << output1_filename << " for writing." << endl;
		return 1;
	}
	ofstream output2(output2_filename.c_str());
	if (output2.fail()) {
		cerr << "Error: could not open " << output2_filename << " for writing." << endl;
		return 1;
	}
	
	po::variables_map options;
	try {
		po::store(po::parse_command_line(argc, argv, options_desc), options);
		po::notify(options);
	} catch(exception& e) {
		cerr << "error: " << e.what() << "\n";
		return 1;
	}
	cerr << "Commandline: " << commandline << endl;

	long long skipped = 0;
	try {
		GroupWiseBamReader bam_reader("/dev/stdin", true);
		while (bam_reader.hasNext()) {
			bam_reader.advance();
			const std::vector<BamTools::BamAlignment*>& alignments1 = bam_reader.getAlignmentsFirst();
			const std::vector<BamTools::BamAlignment*>& alignments2 = bam_reader.getAlignmentsSecond();
			if ((alignments1.size() == 0) || (alignments2.size() == 0)) {
				skipped += 1;
				continue;
			}
			output_read(*(alignments1[0]), output1);
			output_read(*(alignments2[0]), output2);
		}
	} catch(exception& e) {
		cerr << "Error: " << e.what() << "\n";
		return 1;
	}
    if (skipped > 0) {
		cerr << "Skipped " << skipped << " reads." << endl;
    }
	return 0;
}
